﻿using System;
using Trinity.Framework;
using Trinity.Framework.Helpers;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows.Controls;
using Trinity.Components.Combat;
using Trinity.Components.Combat.Resources;
using Trinity.DbProvider;
using Trinity.Framework.Objects;
using Trinity.Framework.Reference;
using Trinity.Framework.Objects.Memory;
using Trinity.UI;
using Zeta.Common;
using Zeta.Game;
using Zeta.Game.Internals.Actors;


namespace Trinity.Routines.Witchdoctor
{
    public sealed class AbnormalWitchDoctorSpiritBarrage : WitchDoctorBase, IRoutine
    {
        #region Definition

        public string DisplayName => "不正常人类策略 巫医散件魂淡";
        public string Description => "初版，以原版亚基拉火符策略改造，欢迎各路大神来QQ群469549087指导反馈提意见，大家一起来完善本策略吧";
        public string Author => "不正常人类研究所";
        public string Version => "v0.1-20170527";
        public string Url => "http://www.demonbuddy.cn/thread-12411-1-1.html";

        public Build BuildRequirements => new Build
        {
            Sets = new Dictionary<Set, SetBonus>
            {
                { Sets.LegacyOfNightmares, SetBonus.First },
            },
            Items = new List<Item>
            {
                Legendary.TheBarber
            },
			Skills = new Dictionary<Skill, Rune>
            {
                { Skills.WitchDoctor.SpiritBarrage, null },
				{ Skills.WitchDoctor.LocustSwarm, null },
				{ Skills.WitchDoctor.Haunt, null }
            },
        };

        public override Func<bool> ShouldIgnoreKiting => IgnoreCondition;
        public override Func<bool> ShouldIgnoreAvoidance => IgnoreCondition;
        public override Func<bool> ShouldIgnorePackSize => () => Player.IsChannelling;
        public override Func<bool> ShouldIgnoreNonUnits => () => Player.IsChannelling && Player.CurrentHealthPct > 0.35;

        #endregion

        private bool IgnoreCondition()
        {
            var isInAvoidance = Core.Avoidance.InCriticalAvoidance(Player.Position);
            if (TargetUtil.AnyMobsInRange(FireBatsRange) && Player.CurrentHealthPct > 0.5f && !isInAvoidance)
                return true;

            return Player.IsChannelling && Player.CurrentHealthPct > 0.35 && !Core.Avoidance.InCriticalAvoidance(Player.Position);
        }

        public TrinityPower GetOffensivePower()
        {
            Vector3 position;
            TrinityPower power;

            var allUnits = Core.Targets.ByType[TrinityObjectType.Unit].Where(u => u.IsUnit && u.RadiusDistance <= 50f).ToList();

            var clusterUnits =
                (from u in allUnits
                 where u.IsUnit && u.Weight > 0 && !u.IsPlayer
                 orderby
                 u.NearbyUnitsWithinDistance(15f) descending,
                 u.Distance,
                 u.HitPointsPct descending
                 select u).ToList();

            var bestClusterUnit = clusterUnits.FirstOrDefault();
			var unitsNearDogs = TargetUtil.UnitsWithinRangeOfPet(PetType.Pet0, 60f).ToList();	
			if (bestClusterUnit != null && Skills.WitchDoctor.GraspOfTheDead.CanCast() && Runes.WitchDoctor.DeathIsLife.IsActive && unitsNearDogs.Count < 3)
			{				
				Core.Logger.Warn("生几只狗仔玩玩");
				return GraspOfTheDead(allUnits.FirstOrDefault());
			}
			
			if (Skills.WitchDoctor.Sacrifice.CanCast() && unitsNearDogs.Count >= 1)
				return Sacrifice();
			
            if (bestClusterUnit != null)
            {
                var targetsWithoutLocust = clusterUnits.Where(u => !u.HasDebuff(SNOPower.Witchdoctor_Locust_Swarm)).OrderBy(u => u.Distance);//无瘟疫蝗虫目标
                var isAnyTargetWithLocust = clusterUnits.Any(u => u.HasDebuff(SNOPower.Witchdoctor_Locust_Swarm) && u.Distance < 45f);//有瘟疫蝗虫目标
                var percentTargetsWithHaunt = TargetUtil.DebuffedPercent(SNOPower.Witchdoctor_Haunt, 8f);//蚀魂覆盖百分比
                var percentTargetsWithLocust = TargetUtil.DebuffedPercent(SNOPower.Witchdoctor_Locust_Swarm, 12f);//瘟疫蝗虫覆盖百分比
                var isEliteWithoutHaunt = clusterUnits.Any(u => u.IsElite && !u.HasDebuff(SNOPower.Witchdoctor_Haunt));//无蚀魂精英
                var isElitewithoutLocust = clusterUnits.Any(u => u.IsElite && !u.HasDebuff(SNOPower.Witchdoctor_Locust_Swarm));//无瘟疫蝗虫精英
                var harvestStacks = Skills.WitchDoctor.SoulHarvest.BuffStacks;//收割叠层
                var harvestBuffCooldown = Core.Cooldowns.GetBuffCooldown(SNOPower.Witchdoctor_SoulHarvest);//收割buff冷却
                var harvestPossibleStackGain = 10 - harvestStacks;//收割还可叠的层数
                var harvestUnitsInRange = allUnits.Count(u => u.Distance < 12f);//可收割的范围
                var interruptForHarvest = Skills.WitchDoctor.SoulHarvest.CanCast() && harvestPossibleStackGain >= harvestUnitsInRange && harvestBuffCooldown?.Remaining.TotalMilliseconds < 500;//放收割检查
                var interruptForHaunt = percentTargetsWithHaunt < 0.2f || isEliteWithoutHaunt;//放蚀魂检查			
                var needToSwarmElite = isElitewithoutLocust && !((Legendary.VileHive.IsEquipped || Runes.WitchDoctor.Pestilence.IsActive) && isAnyTargetWithLocust);//需要对精英释放瘟疫虫群
                var interruptForLocust = (percentTargetsWithLocust < 0.1f || needToSwarmElite) && Player.PrimaryResource > 300 && Skills.WitchDoctor.LocustSwarm.CanCast();//放瘟疫虫群检查					

                if (Player.IsChannelling)
                {
                    if (!interruptForHaunt && !interruptForLocust && !interruptForHarvest)
                    {
                        Core.Logger.Error("是时候扔魂弹了.");
						return new TrinityPower(SNOPower.Witchdoctor_SpiritBarrage, 10f, targetsWithoutLocust.First().Position, 0, 0);
                    }

                   /* if (interruptForHaunt)
                        Core.Logger.Log(LogCategory.Routine, "是时候补充蚀魂了");

                    if (interruptForLocust)
                        Core.Logger.Log(LogCategory.Routine, "是时候补充瘟疫虫群了");

                    if (interruptForHarvest)
                        Core.Logger.Log(LogCategory.Routine, "是时候补充灵魂收割了");
					*/
                }

                if (Player.CurrentHealthPct < 0.5)
                {
                    if (Skills.WitchDoctor.SpiritWalk.CanCast())
                    {
                        return SpiritWalk();
                    }

                    if (TargetUtil.AnyMobsInRange(12f) && Skills.WitchDoctor.SoulHarvest.CanCast())
                    {
                        return SoulHarvest();
                    }
                }

                // 蝗虫来袭
                if (Skills.WitchDoctor.LocustSwarm.CanCast() && Skills.WitchDoctor.LocustSwarm.TimeSinceUse > 1000 && targetsWithoutLocust.Any() && (!Runes.WitchDoctor.Pestilence.IsActive || !isAnyTargetWithLocust))
                {
                    if ((percentTargetsWithLocust < Settings.LocustPct || needToSwarmElite) && Player.PrimaryResource > 300 && targetsWithoutLocust.Any())
                    {
                        return new TrinityPower(SNOPower.Witchdoctor_Locust_Swarm, 10f, targetsWithoutLocust.First().Position, 0, 0);
                    }
                }

                // 收割收割收割
                if (Skills.WitchDoctor.SoulHarvest.CanCast() && (bestClusterUnit.Distance < 12f || harvestStacks < 4 && TargetUtil.AnyMobsInRange(10f)) && harvestStacks < 10)
                {
                    if (harvestPossibleStackGain <= harvestUnitsInRange)
                    {
                        return SoulHarvest();
                    }
                }

                // 食人鱼
                if (Skills.WitchDoctor.Piranhas.CanCast() && Player.PrimaryResource >= 250 &&
                    (TargetUtil.ClusterExists(15f, 40f) || TargetUtil.AnyElitesInRange(40f)) && Player.PrimaryResource >= 250)
                {
					Core.Logger.Warn("丢你们进去喂鱼噢");
                    return Piranhas(TargetUtil.GetBestClusterUnit());
                }
               
                var targetsWithoutHaunt = clusterUnits.Where(u => !u.HasDebuff(SNOPower.Witchdoctor_Haunt) && !SpellTracker.IsUnitTracked(u, SNOPower.Witchdoctor_Haunt)).OrderBy(u => u.Distance);
                if ((percentTargetsWithHaunt < Settings.HauntPct || isEliteWithoutHaunt) && targetsWithoutHaunt.Any() && Player.PrimaryResource > 100)
                {
                    var target = targetsWithoutHaunt.First();
                    return Haunt(target);
                }

                Vector3 bestBuffedPosition;
                TargetUtil.BestBuffPosition(16f, bestClusterUnit.Position, true, out bestBuffedPosition);
                var bestClusterUnitRadiusPosition = MathEx.GetPointAt(bestClusterUnit.Position, bestClusterUnit.CollisionRadius * 1.1f, bestClusterUnit.Rotation);
                var bestSpiritBarragePosition = bestBuffedPosition != Vector3.Zero ? bestBuffedPosition : bestClusterUnitRadiusPosition;
                var distance = bestSpiritBarragePosition.Distance(Player.Position);

                if (distance > 10f && !PlayerMover.IsBlocked)
                {
                    if (distance > 20f && Skills.WitchDoctor.SpiritWalk.CanCast())
                    {
                        Core.Logger.Warn("看我月球漫步");
                        return SpiritWalk();
                    }
  
                    return new TrinityPower(SNOPower.Walk, 3f, bestSpiritBarragePosition, 0, 0);
                }

                if (Skills.WitchDoctor.SpiritBarrage.CanCast())
                {
                    var closestUnit = allUnits.OrderBy(u => u.Distance).FirstOrDefault();
                    if (closestUnit != null)
                    {
                        Core.Logger.Error("前方要爆炸！");
                        return SpiritBarrage(closestUnit);
                    }
                }
            }

            return Walk(TargetUtil.GetLoiterPosition(CurrentTarget, 15f));
        }

        public TrinityPower GetBuffPower()
        {
            Vector3 position;

            if (Settings.SpiritWalk.UseMode == UseTime.Always && Skills.WitchDoctor.SpiritWalk.CanCast())
                return SpiritWalk();

            if (ShouldSpiritWalk())
                return SpiritWalk();

            if (ShouldFetishArmy())
                return FetishArmy();

            if (Skills.WitchDoctor.SoulHarvest.CanCast() && (!IsChannellingFirebats || Player.CurrentHealthPct < 0.4f) && HostileMonsters.Any(u => u.Distance < 16f))
            {
                // 尽量避免丢失收割buff.
                if (Skills.WitchDoctor.SoulHarvest.TimeSinceUse > 4500)
                    return SoulHarvest();

                if (Skills.WitchDoctor.SoulHarvest.BuffStacks < MaxSoulHarvestStacks)
                    return SoulHarvest();
            }

            return null;
        }

        public TrinityPower GetDefensivePower() => GetBuffPower();
        public TrinityPower GetDestructiblePower() => DefaultDestructiblePower();
        public TrinityPower GetMovementPower(Vector3 destination)
        {
            if (Skills.WitchDoctor.SpiritWalk.CanCast() && Player.CurrentHealthPct < 0.5f)
            {
                    return SpiritWalk();
            }

            return Walk(destination);
        }

        #region Settings

        public override int ClusterSize => Settings.ClusterSize;
        public override float EmergencyHealthPct => Settings.EmergencyHealthPct;
        public override float KiteDistance => 5f;
        public override int KiteHealthPct => 90;

        IDynamicSetting IRoutine.RoutineSettings => Settings;
        public AbnormalWitchDoctorSpiritBarrageSettings Settings { get; } = new AbnormalWitchDoctorSpiritBarrageSettings();

        public sealed class AbnormalWitchDoctorSpiritBarrageSettings : NotifyBase, IDynamicSetting
        {
            private int _clusterSize;
            private float _emergencyHealthPct;
            private SkillSettings _spiritWalk;
                        private float _hauntPct;
            private float _locustPct;

            [DefaultValue(8)]
            public int ClusterSize
            {
                get { return _clusterSize; }
                set { SetField(ref _clusterSize, value); }
            }

            [DefaultValue(0.4f)]
            public float EmergencyHealthPct
            {
                get { return _emergencyHealthPct; }
                set { SetField(ref _emergencyHealthPct, value); }
            }

            public SkillSettings SpiritWalk
            {
                get { return _spiritWalk; }
                set { SetField(ref _spiritWalk, value); }
            }

            [DefaultValue(0.35f)]
            public float LocustPct
            {
                get { return _locustPct; }
                set { SetField(ref _locustPct, value); }
            }
             
            [DefaultValue(0.35f)]
            public float HauntPct
            {
                get { return _hauntPct; }
                set { SetField(ref _hauntPct, value); }
            }

            private static readonly SkillSettings DefaultSpiritWalkSettings = new SkillSettings
            {
                UseMode = UseTime.Default,
            };

            public override void LoadDefaults()
            {
                base.LoadDefaults();
                SpiritWalk = DefaultSpiritWalkSettings.Clone();
            }

            #region IDynamicSetting

            public string GetName() => GetType().Name;
            public UserControl GetControl() => UILoader.LoadXamlByFileName<UserControl>(GetName() + ".xaml");
            public object GetDataContext() => this;
            public string GetCode() => JsonSerializer.Serialize(this);
            public void ApplyCode(string code) => JsonSerializer.Deserialize(code, this, true);
            public void Reset() => LoadDefaults();
            public void Save() { }

            #endregion
        }

        #endregion
    }
}


